package org.orbis.search;

import org.msgpack.MessagePackObject;
import org.msgpack.object.ArrayType;
import org.msgpack.object.BooleanType;
import org.msgpack.object.IntegerType;
import org.msgpack.object.RawType;
import org.orbis.communicate.FlagsResult;
import org.orbis.flag.SearchFlags;
import org.orbis.structure.ContentInfo;

public class SearchPackage{
	private String query;
	private byte[] type;
	private boolean andSearch;
	private int from, length;
	private SearchFlags flags;
//	private ContentInfo contentInfo;

	private SearchPackage(){}

	private SearchPackage(String newQuery, byte[] type, boolean andSearch, int from, int length){
		this.query = newQuery;
		this.type = type;
		this.andSearch = andSearch;
		this.from = from;
		this.length = length;
	}

	public static SearchPackage createPackage(String newQuery, int from, int length, boolean andSearch,
		ContentInfo contentInfo){
		SearchPackage pkg = new SearchPackage();
		pkg.query = newQuery;
		pkg.from = from - 1;
		if(pkg.from < 0) pkg.from = 0;
		pkg.length = length;
		if(pkg.length < 1) pkg.length = 1;
		pkg.type = new byte[contentInfo.contentsNum()];
		pkg.andSearch = andSearch;
		pkg.flags = new SearchFlags(contentInfo);
//		pkg.contentInfo = contentInfo;

		return pkg;
	}

	public void setType(int index, boolean isTarget){
		if(index >= type.length) return;
		this.type[index] = (byte)(isTarget? 1: 0);
	}

	public void setBinaryFlag(int index, byte value){
		this.flags.setBinaryFlags(index, value);
	}

	public void setBinaryFlags(byte[] types){
		this.type = types;
	}

	public byte[] binaryFlags(){
		return flags.getBinaryFlags();
	}

	public void setIntFlag(int index, int type, int rangeFrom, int rangeTo){
		this.flags.setIntFlags(index, type, rangeFrom, rangeTo);
	}

	public void setLongFlag(int index, int type, long rangeFrom, long rangeTo){
		this.flags.setLongFlags(index, type, rangeFrom, rangeTo);
	}

	public void setFloatFlag(int index, int type, float rangeFrom, float rangeTo){
		this.flags.setFloatFlags(index, type, rangeFrom, rangeTo);
	}

	public SearchFlags flags(){
		return flags;
	}

	public String query(){
		return query;
	}

	public int from(){
		return from;
	}

	public int length(){
		return length;
	}

	public void setLength(FlagsResult[] results){
		int count = 0;
		if(results == null){
			this.length = 0;
			return;
		}
		for(int i = 0; i < results.length; i++){
			if(results[i] != null) count++;
		}
		if(this.length > count) this.length = count;
	}

	public byte[] searchTypes(){
		return type;
	}
	
	public boolean[] searchTypesBool() {
		boolean[] bools = new boolean[type.length];
		for(int i = 0; i < bools.length; i++){
			if(type[i] == 1) bools[i] = true;
			else bools[i] = false;
		}
		
		return bools;
	}

	public boolean searchType(int index){
		if(index >= type.length) return false;
		return type[index] == 1? true: false;
	}

	public boolean isAndSearch(){
		return andSearch;
	}

	public static final int HEADER = 'p' << 24 | 's' << 16 | 'e' << 8 | 'r';

	public static SearchPackage unpack(ArrayType array){
		MessagePackObject[] object = array.asArray();

		int header = object[0].asInt();
		if(header != HEADER) return null;
		SearchPackage pkg =
			new SearchPackage(object[1].asString(), object[2].asByteArray(), object[3].asBoolean(),
				object[4].asInt(), object[5].asInt());
		pkg.flags = SearchFlags.unpack(object, 6);

		return pkg;
	}

	public ArrayType pack(){
		MessagePackObject[] object = new MessagePackObject[6 + flags.packSize()];
		object[0] = IntegerType.create(HEADER);
		object[1] = RawType.create(query);
		object[2] = RawType.create(type);
		object[3] = BooleanType.create(andSearch);
		object[4] = IntegerType.create(from);
		object[5] = IntegerType.create(length);
		flags.pack(object, 6);

		return ArrayType.create(object);
	}
}
